public class BitOpTester {

    private static final int BYTE_OFFSET = 128;

    public static void main(String[] args) {

        int offset = 750;

        final int SET_DO_NOT_FRAGMENT = 0x4000;
        final int SET_MORE_BITS = 0x2000;

        int value = offset | SET_DO_NOT_FRAGMENT;

        // System.out.println("Offset: " + Integer.toBinaryString(offset));
        //
        // System.out.println("Value:  " + Integer.toBinaryString(value));
        //
        // value = value | SET_MORE_BITS;
        //
        // System.out.println("Value:  " + Integer.toBinaryString(value));
        //
        // value = value ^ SET_MORE_BITS;
        //
        // System.out.println("Value:  " + Integer.toBinaryString(value));
        //
        // value = value ^ SET_DO_NOT_FRAGMENT;
        //
        // System.out.println("Value:  " + Integer.toBinaryString(value));
        //
        // value = value / 2;
        //
        // System.out.println("Value:  " + Integer.toBinaryString(value));
        //
        // value = value | SET_DO_NOT_FRAGMENT;
        // value = value | SET_MORE_BITS;
        //
        // System.out.println("Value:  " + Integer.toBinaryString(value));

        int[] data1 = { 0x4500, 0x0073, 0x0000, 0x4000, 0x4011 /* , 0xb861 */,
                0xc0a8, 0x0001, 0xc0a8, 0x00c7 };
        int[] data2 = { 0x4500, 0x0073, 0x0000, 0x4000, 0x4011, 0xb861, 0xc0a8,
                0x0001, 0xc0a8, 0x00c7 };
        
        int[] data3 = {69, 0, 128, 160, 128, 143, 226, 61, 127, 6, 0, 91, 255, 0, 0, 16, 128, 128, 255, 255};
        int[] data4 = {69, 0, 128, 160, 226, 61, 127, 6, 0, 91, 255, 0, 0, 16, 128, 128, 255, 255};
        
        int[] data5 = {69, 0, 0, 115, 0, 0, 64, 0, 64, 17, 184, 97, 192, 168, 0, 1, 192, 168, 0, 199};
        int[] data6 = {69, 0, 0, 115, 0, 0, 64, 0, 64, 17, 192, 168, 0, 1, 192, 168, 0, 199};

//        System.out.println(Integer.toHexString((calculateChecksum(data))));
//        System.out.println();
//        System.out.println(validateChecksum(data2, calculateChecksum(data)));
//
//        System.out.println(Integer.toBinaryString(149404));
        

//        byteToStringToSum();
        
//        intToStringToSum();
        
        byte[] data = new byte[data5.length];
        
        for (int i = 0; i < data.length; i++) {
            data[i] = (byte)(data5[i] - BYTE_OFFSET);
        }
        
        System.out.println(sumDatagramArray(data));
        
    }
    
    private static void intToStringToSum(int[] data) {

        
        int b1 = 0;
        int b2 = 0;
        
        int sum = 0;
        
        for (int i = 0; i < data.length; i = i + 2) {
            b1 = data[i];
            b2 = data[i + 1];
            
            String leftByte = String.format("%2s",
                    Integer.toHexString(b1)).replace(' ', '0');
            String rightByte = String.format("%2s",
                    Integer.toHexString(b2)).replace(' ', '0');
            
            String sumString = String.format("%2s",
                    Integer.toBinaryString(sum)).replace(' ', '0');
            
            String twoBytes = (leftByte + rightByte);
            System.out.println("[leftByte]  " + leftByte);
            System.out.println("[rightByte] " + rightByte);
            System.out.println("[twoBytes]  " + twoBytes);
            
            System.out.println(Integer.parseInt(twoBytes, 16));
            
            sum += Integer.parseInt(twoBytes, 16);
        }
        
        System.out.println("[sum]       " + sum);
    }
    
    
    private static void byteToStringToSum() {
        byte[] data1 = {-59, -128, 0, 32, 0, 15, 98, -67, -1, -122, -128, -37, 127, -128, -128, -112, 0, 0, 127, 127};
        byte[] data2 = {-59, -128, 0, 32, 98, -67, -1, -122, -128, -37, 127, -128, -128, -112, 0, 0, 127, 127};
        int[] data3 = {69, 0, 128, 160, 226, 61, 127, 6, 0, 91, 255, 0, 0, 16, 128, 128, 255, 255};
        
        byte b1 = 0;
        byte b2 = 0;
        
        int sum = 0;
        
        for (int i = 0; i < data2.length; i = i + 2) {
            b1 = data2[i];
            b2 = data2[i + 1];
            
            String leftByte = Integer.toHexString(b1 & 0xFF00);
            String rightByte = Integer.toHexString(b2 & 0xFF);
            
            String twoBytes = (leftByte + rightByte);
//            System.out.println("[leftByte]  " + leftByte);
//            System.out.println("[rightByte] " + rightByte);
//            System.out.println("[twoBytes]  " + twoBytes);
            
//            System.out.println(Integer.parseInt(twoBytes, 16));
            
            sum += Integer.parseInt(twoBytes, 16);
        }
        
        System.out.println("[sum]       " + sum);
    }

    private static short calculateChecksum(int[] data) {
        final int BIT_MASK = 0xF000;
        int value = 0;

        int sum = 0;

        for (int i = 0; i < data.length; i++) {
            sum += data[i];
        }

        String s = Integer.toBinaryString(sum);

        String temp = reverseString(s);

        String s1 = temp.substring(16);
        s1 = reverseString(s1);
        int first = Integer.valueOf(s1, 2);

        String s2 = temp.substring(0, 16);
        s2 = reverseString(s2);
        int second = Integer.valueOf(s2, 2);

        sum = first + second;

        sum = ~sum;

        return (short) sum;
    }

    private static boolean validateChecksum(int[] data, short value) {
        int sum = 0;

        for (int i = 0; i < data.length; i++) {
            sum += data[i];
        }

        String sumString = Integer.toBinaryString(sum);

        sumString = reverseString(sumString);

        int carry = 0;

        if (sumString.length() > 15) {
            String s1 = sumString.substring(16);
            s1 = reverseString(s1);
            carry = Integer.valueOf(s1, 2);
        }

        int restOfSum = 0;

        if (sumString.length() > 15) {
            String s2 = sumString.substring(0, 16);
            s2 = reverseString(s2);
            restOfSum = Integer.valueOf(s2, 2);
        } else {
            sumString = reverseString(sumString);
            restOfSum = Integer.valueOf(sumString, 2);
        }

        sum = carry + restOfSum;

        sum = (short) ~sum;

        if (sum == 0) {
            return true;
        }

        return false;
    }

    private static String reverseString(String s) {
        StringBuffer sb = new StringBuffer(s).reverse();

        return sb.toString();
    }
    
    private static int sumDatagramArray(byte[] data) {
        int[] temp = new int[data.length];

        // Correct for byte offset to avoid signed bits.
        for (int i = 0; i < data.length; i++) {
            temp[i] = data[i] + BYTE_OFFSET;
        }
             
        // Collect 16-bit values by assembling a hex-value pair of "bytes".
        int b1 = 0;
        int b2 = 0;
        int sum = 0;
        
        for (int i = 0; i < temp.length; i = i + 2) {
            b1 = temp[i];
            b2 = temp[i + 1];
            
            String leftByte = String.format("%2s",
                    Integer.toHexString(b1)).replace(' ', '0');
            String rightByte = String.format("%2s",
                    Integer.toHexString(b2)).replace(' ', '0');
            
            String sumString = String.format("%2s",
                    Integer.toBinaryString(sum)).replace(' ', '0');
            
            String twoBytes = (leftByte + rightByte);
//            System.out.println("[leftByte]  " + leftByte);
//            System.out.println("[rightByte] " + rightByte);
//            System.out.println("[twoBytes]  " + twoBytes);
//            
//            System.out.println(Integer.parseInt(twoBytes, 16));
//            
            sum += Integer.parseInt(twoBytes, 16);
        }

        return sum;
    }
}
